

#ifndef __CCPP_POLYGON_2D_H__
#define __CCPP_POLYGON_2D_H__

#include "common/cgal_def.h"

#include <unordered_map>

/**
 * @file
 * @brief Define the Polygon2D class.
 */

#pragma once

/**
 * @namespace global_plan_path::ccpp
 * @brief global_plan_path::ccpp
 */
namespace global_path_planner
{
    namespace ccpp
    {

        /**
         * @class Polygon2D
         * @brief The class of Polygon2D in 2-D.
         */

        class Polygon2D
        {
        public:
            /**
             * @brief Empty constructor.
             */
            Polygon2D() = default;

            // 点与多边形的关系
            bool pointInPolygon(const Polygon_2 &poly, const Point_2 &p);

            bool pointsInPolygon(const Polygon_2 &poly, const std::vector<Point_2> &pts);

            // 判断多边形是否有多个交叉点
            bool isStrictlySimple(const Polygon_2 &poly);

            // 创建polygon2
            bool createPolygon2(Polygon_2* poly);

            // 点映射到多边形最长距离.
            std::pair<FT, Point_2> projectOnPolygon2(const Polygon_2 &poly, const Point_2 &p);

            //  计算点到多边形的最小距离
            FT minDistOfPonit2ToPolygon2(const Polygon_2 &poly, const Point_2 &p);

            // 计算多边形的面积
            FT computeArea(const Polygon_2 &poly);

            // 删除共线的顶点
            void removeCollinearVertices(Polygon_2 *polygon);

            // 旋转多边形
            Polygon_2 rotatePolygon(const Polygon_2 &polygon_in,
                                    const Direction_2 &dir);

            // 判断多边形的顺逆性
            bool IsClockwise(Polygon_2& poly);

            // 生成单一结构的多多边形
            std::vector<Polygon_2> GenSimplePolys(std::vector<Polygon_2>& not_simple_polys, bool is_out_poly);

            // 计算多边形之间是否存在交叉
            std::pair<std::vector<std::pair<EdgeConstIterator, Point_2>>,
            std::vector<std::pair<EdgeConstIterator, Point_2>>>
                PolygonsIntersection(Polygon_2 &out_polys, Polygon_2 &hole_polys);

            // polygon是否存在交叉点
            std::vector<std::tuple<VertexConstIterator, VertexConstIterator, Point_2>>
                PolygonIntersection(Polygon_2 &poly);

            // 凹边形转凸边形
            std::vector<Polygon_2> ConcaveToConvex(Polygon_2& polygon, EdgeConstIterator& dir);

            // 根据多边形交叉点分成多个多边形
            std::vector<Polygon_2> splitPolygonByInsection(Polygon_2 &poly, bool is_out_poly);

            // 根据critical_vertice分割多边形
            std::vector<Polygon_2> splitPolygonByCritical(const Polygon_2& polygon,
                    const std::vector<Point_2>& intersections, const Point_2& critical_vertice);

            // Polygon存在交叉点分为几个更小的polygon
            std::vector<Polygon_2> removeNotSimplePolygonPoints(Polygon_2 &polys, bool outer_hole, Point_2 start = Point_2());

            // Sorts the given list of vertices by x coordinate. If equal, lower y coordinate is placed first.
            void sortVertices(Polygon_2 &poly);
            void sortVertices(std::vector<Point_2> &vertices);
            void sortVertices(std::vector<VertexConstCirculator>& vertices);

            // 计算多边形顶点到直线的距离，然后对顶点排序
            std::vector<Point_2> sortVerticesToLine(const Polygon_2& poly, const Line_2 &l);

            // 获取多边形的顶点
            std::vector<Point_2> getVertices(const Polygon_2 &poly);

            //获取>180度的顶点作为关键点
            std::vector<Point_2> getCriticalInflectionPoints(Polygon_2& polygon);

            // 获取segments
            std::pair<bool, std::vector<Segment_2>> getSegments(const Polygon_2& poly, const Line_2& line);

            // 线段与多边形相交
            std::vector<Point_2> getIntersectionPoints(const Polygon_2 &polygon, const Line_2 &line);

            std::vector<Point_2> getIntersectionPoints(const Polygon_2 &polygon, const Segment_2 &segment);

            // 查找点是否在多边形顶点中
            VertexIterator findPointInPolygon2(const Point_2 &point, const Polygon_2 &poly);

            // 合并两个多边形
            Polygon_2 mergePolygons(const Polygon_2 &poly_1, const Polygon_2 &poly_2);

            // 合并有交叉的不同多边形
            Polygon_2 MergeIntersectionPolygons(Polygon_2 &out_polys, Polygon_2 &hole_polys, bool sweep_merge = true);

            // 点插入到多边形
            void insertPointAlongEdge(const Point_2 &point, Polygon_2 &poly);

            // 获取多边形所有的边
            std::vector<Direction_2> getPolygonEdgeDirections(const Polygon_2 &poly);

            private:
                //获取顶点的角度
                double getInteriorAngleOfVertex(const Polygon_2::Vertex_const_circulator& vertex);

                // 构造凸边形
                std::vector<Polygon_2> createConvex(Polygon_2& polygon, EdgeConstIterator& dir, std::vector<Polygon_2>& convex_polys);

                // 顺时针排序交叉点构成的边
                std::unordered_map<int, std::vector<std::pair<EdgeConstIterator, Point_2>>> 
                    sortEdgeByIntersectPoints(std::vector<std::pair<EdgeConstIterator, Point_2>>& edge_insects);

                // 根据交叉点起点和终点重排顶点
                std::vector<Point_2> sortVertexByIntersectPoints(Polygon_2& polys, Point_2& seg_start, 
                                                                Point_2& seg_end, Point_2& start, 
                                                                Point_2& end, bool flag = true);

                // 交叉点相等时，分别提取轮廓边一定距离作为交叉的起点和终点
                Point_2 InterceptEdgePoint(Point_2& start, Point_2& end);
        };

    } // namespace ccpp
} // global_plan_path

#endif // __CCPP_POLYGON_2D_H__